package com.glp.work.flow.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.glp.work.flow.constant.APICode;
import com.glp.work.flow.constant.CodeFactorEnum;
import com.glp.work.flow.constant.Constants;
import com.glp.work.flow.exception.APIException;
import com.glp.work.flow.exception.WorkflowException;
import com.glp.work.flow.mapper.WfFormExampleMapper;
import com.glp.work.flow.mapper.WfFormMapper;
import com.glp.work.flow.pojo.WfForm;
import com.glp.work.flow.pojo.WfFormExample;
import com.glp.work.flow.request.WfFormDTO;
import com.glp.work.flow.service.CodeService;
import com.glp.work.flow.service.WfFormService;
import com.glp.work.flow.utils.DataUtils;
import com.glp.work.flow.workflow.plugin.flowable.service.FlowProcessDefinitionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 表单服务
 *
 * @author jhuang1
 */
@Slf4j
@Service
public class WfFormServiceImpl implements WfFormService {

    @Resource
    private WfFormMapper wfFormMapper;
    @Resource
    private WfFormExampleMapper wfFormExampleMapper;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    @Resource
    private CodeService codeService;
    @Resource
    private FlowProcessDefinitionService flowProcessDefinitionService;

    @Override
    public PageInfo<WfFormDTO> queryFormList(WfFormDTO wfFormDTO) {
        Example example = new Example(WfForm.class);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(wfFormDTO.getFormCode())) {
            criteria.andEqualTo("formCode", wfFormDTO.getFormCode());
        }
        if (StringUtils.isNotBlank(wfFormDTO.getFormName())) {
            criteria.andLike("formName", "%" + wfFormDTO.getFormName() + "%");
        }
        PageMethod.startPage(wfFormDTO.getPageNum(), wfFormDTO.getPageSize());
        List<WfForm> list = wfFormMapper.selectByExample(example);
        list.forEach(l -> l.setFormContent(null));
        PageInfo<WfForm> pageInfo = new PageInfo<>(list);
        pageInfo.setPageSize(wfFormDTO.getPageSize());
        pageInfo.setPageNum(wfFormDTO.getPageNum());
        log.info("表单列表查询,查询记录数:{}", pageInfo.getList().size());
        return DataUtils.pageInfo2PageInfoDTO(pageInfo, WfFormDTO.class);
    }

    @Override
    public void insertForm(WfForm wfForm) {
        Example example = new Example(WfForm.class);
        example.createCriteria().andEqualTo("formCode", wfForm.getFormCode());
        List<WfForm> formList = wfFormMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(formList)) {
            throw new APIException(APICode.DATA_ERROR, "表单编号已存在！");
        }
        if (StringUtils.isBlank(wfForm.getStatus())) {
            wfForm.setStatus(Constants.STATUS_1);
        }
        wfForm.setCreateTime(new Date());
        wfForm.setFormCode(codeService.generateWithDigits(CodeFactorEnum.BD.name(), 6));
        wfFormMapper.insert(wfForm);
        log.info("新增表单模板--完成--，记录:{}", wfForm);
    }

    @Override
    public void updateForm(WfForm wfForm) {
        Example example = new Example(WfForm.class);
        example.createCriteria().andEqualTo("id", wfForm.getId());
        WfForm dbForm = wfFormMapper.selectOneByExample(example);
        if (null == dbForm) {
            throw new APIException(APICode.DATA_ERROR, "表单模板不存在！");
        }
        example.clear();
        example.createCriteria()
                .andEqualTo("formCode", wfForm.getFormCode())
                .andNotEqualTo("id", wfForm.getId());
        List<WfForm> formList = wfFormMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(formList)) {
            throw new APIException(APICode.DATA_ERROR, "表单编号已存在！");
        }
        int i = wfFormMapper.updateByPrimaryKeySelective(wfForm);
        log.info("修改表单模板--完成--，修改记录数:{}", i);
    }

    @Override
    public void updateFormStatus(WfForm wfForm) {
        Example example = new Example(WfForm.class);
        example.createCriteria().andEqualTo("id", wfForm.getId());
        WfForm dbForm = wfFormMapper.selectOneByExample(example);
        if (null == dbForm) {
            throw new APIException(APICode.DATA_ERROR, "表单模板不存在！");
        }
        int i = wfFormMapper.updateByPrimaryKeySelective(wfForm);
        log.info("修改表单状态--完成--，修改记录数:{}", i);
    }

    @Override
    public WfForm queryFormDetail(Long id) {
        return wfFormMapper.selectByPrimaryKey(id);
    }

    @Transactional(rollbackOn = Exception.class)
    @Override
    public void initForm(String procDefKey, String processId, Map<String, Object> dynamicForm) {
        log.info("procDefKey：{},processId:{},初始化表单", procDefKey, processId);
        List<UserTask> userTaskList = flowProcessDefinitionService.getUserTaskList(procDefKey);
        if (CollectionUtils.isEmpty(userTaskList)) {
            log.info("procDefKey：{},processId:{},无用户操作节点,不需要实例化表单", procDefKey, processId);
            return;
        }
        List<String> formKeyList = userTaskList.stream().map(UserTask::getFormKey).distinct().collect(Collectors.toList());
        formKeyList.removeAll(Collections.singleton(null));
        if (CollectionUtils.isEmpty(formKeyList)) {
            log.info("procDefKey：{},processId:{},节点未配置formKey", procDefKey, processId);
            WfFormExample wfFormExample = new WfFormExample();
            wfFormExample.setProcessId(processId);
            wfFormExample.setFormData(JSON.toJSONString(dynamicForm));
            wfFormExample.setProcessData(JSON.toJSONString(dynamicForm));
            wfFormExample.setStatus(Constants.STATUS_1);
            wfFormExampleMapper.insertSelective(wfFormExample);
        } else {
            Example example = new Example(WfForm.class);
            example.createCriteria().andIn("formCode", formKeyList)
                    .andEqualTo("status", Constants.STATUS_1);
            List<WfForm> wfFormList = wfFormMapper.selectByExample(example);
            if (formKeyList.size() != wfFormList.size()) {
                log.info("工作流定义formKey数量与表单模板数量不符！formKeyList:{}, wfFormList:{}", formKeyList, wfFormList);
                throw new WorkflowException(APICode.DATA_ERROR, "工作流定义formKey不存在或已禁用！");
            }
            //表单实例入库
            initFormExample(processId, wfFormList, dynamicForm);
        }
    }

    private void initFormExample(String processId, List<WfForm> wfFormList, Map<String, Object> dynamicForm) {
        WfFormExample wfFormExample = new WfFormExample();
        wfFormExample.setProcessId(processId);
        wfFormExample.setFormData(JSON.toJSONString(dynamicForm));
        wfFormExample.setProcessData(JSON.toJSONString(dynamicForm));
        wfFormExample.setStatus(Constants.STATUS_1);
        int insert = wfFormExampleMapper.insertSelective(wfFormExample);
        for (WfForm wfForm : wfFormList) {
            WfFormExample example = new WfFormExample();
            example.setParentId(wfFormExample.getId());
            example.setProcessId(processId);
            example.setStatus(Constants.STATUS_1);
            example.setFormId(wfForm.getId());
            example.setFormCode(wfForm.getFormCode());
            example.setFormName(wfForm.getFormName());
            example.setFormContent(wfForm.getFormContent());
            insert += wfFormExampleMapper.insert(example);
        }
        log.info("processId:{},表单初始化记录数：{}", processId, insert);
    }


    @Override
    public WfFormExample queryFormExample(String processId) {
        //获取当前任务节点，兼容多实例的情况
        List<Task> list = taskService.createTaskQuery().processInstanceId(processId).active().list();
        if (CollectionUtils.isEmpty(list)) {
            log.info("processId:{},当前流程实例无活动任务", processId);
            return null;
        }
        Task task = list.get(0);
        return wfFormExampleMapper.selectByProcessId(processId, task.getFormKey());
    }

    @Override
    public WfFormExample queryFormExampleByTaskId(String proccessId, String taskId) {
        //获取当前任务节点，兼容多实例的情况
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (null == task) {
            log.info("taskId:{}，当前任务不存在！", taskId);
            return null;
        }
        return wfFormExampleMapper.selectByProcessId(proccessId, task.getFormKey());
    }


    @Override
    public WfFormExample queryHistoryFormExample(String processId) {
        String formKey = "";
        List<Task> list = taskService.createTaskQuery().processInstanceId(processId).list();
        if (CollectionUtils.isNotEmpty(list)) {
            for (Task task : list) {
                if (task.getFormKey() != null) {
                    formKey = task.getFormKey();
                    break;
                }
            }
        }

        if (StringUtils.isNotBlank(formKey)) {
            return wfFormExampleMapper.selectByProcessId(processId, formKey);
        } else {
            List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processId).finished().orderByHistoricTaskInstanceEndTime().desc().list();
            if (CollectionUtils.isEmpty(historicTaskInstanceList)) {
                log.info("processId:{},无当前实例操作历史任务", processId);
                return null;
            }
            for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
                if (StringUtils.isNotBlank(historicTaskInstance.getFormKey())) {
                    formKey = historicTaskInstance.getFormKey();
                    break;
                }
            }
        }
        return wfFormExampleMapper.selectByProcessId(processId, formKey);
    }

    @Override
    public void updateFormData(String processId, Map<String, Object> formData) {
        try {
            log.info("processId:{},更新表单数据formData:{}", processId, formData);
            Example example = new Example(WfFormExample.class);
            example.createCriteria().andEqualTo("processId", processId).andIsNull("parentId");
            WfFormExample wfFormExample = wfFormExampleMapper.selectOneByExample(example);
            if (null == wfFormExample) {
                log.info("processId:{},没有查询到表单数据实例", processId);
                return;
            }
            WfFormExample updateExample = new WfFormExample();
            updateExample.setProcessData(JSON.toJSONString(formData));
            int i = wfFormExampleMapper.updateByExampleSelective(updateExample, example);
            log.info("processId:{},更新表单数据结果:{}", processId, i);
        } catch (Exception e) {
            log.error("processId:{},更新表单数据异常！", processId, e);
        }
    }

    @Override
    public int findActRuExecution(String procDefId) {
        return wfFormMapper.findActRuExecution(procDefId);
    }

    @Override
    public int findActRuTaskByFormKey(String formKey) {
        return wfFormMapper.findActRuTaskByFormKey(formKey);
    }
}
